package adtl;

%%

%class Lexer
%cup
%public
%type Token
%line
%scanerror LexicalError

%{
StringBuffer string = new StringBuffer();

public int getLineNumber() { return yyline + 1; }
%}

%eofval{
  return new Token(sym.EOF, getLineNumber());
%eofval}

ALPHA=[A-Za-z]
DIGIT=[0-9]
WHITE_SPACE_CHAR=[\n\r\ \t\b\012]
WHITE_SPACE_CHAR2=[\n\r\ \t\b\012]
STRING_TEXT=(\\\"|[^\n\r\"]|\\{WHITE_SPACE_CHAR}+\\)*
STRING_TEXT2=(xxx[\x00-\x7F]+xxx)*
IDENTIFIER = (_|{ALPHA})({ALPHA}|{DIGIT}|_)*
ILLEGALINTEGER = 0[0-9][0-9]*
INTEGER = 0 | [1-9][0-9]*

/* comments */
InputCharacter = [^\r\n]
Comment = {TraditionalComment} | {EndOfLineComment} | 
          {DocumentationComment}

TraditionalComment = "/*" [^*] ~"*/" | "/*" "*"+ "/"
EndOfLineComment = "//" {InputCharacter}* {LineTerminator}?
DocumentationComment = "/*" "*"+ [^/*] ~"*/"

LineTerminator = \r|\n|\r\n
WhiteSpace = {LineTerminator} | [ \t\f]

%state STRINGSTATE

%%

<YYINITIAL> {

  \"           { string.setLength(0); yybegin(STRINGSTATE); }
  "/"          { return new Token(yytext(), sym.DIVIDE, getLineNumber()); }
  "{"          { return new Token(yytext(), sym.LCBR, getLineNumber()); }
  "<="          { return new Token(yytext(), sym.LTE, getLineNumber()); }
  "rev"          { return new Token(yytext(), sym.REV, getLineNumber()); }
  ";"          { return new Token(yytext(), sym.SEMI, getLineNumber()); }
  "-"          { return new Token(yytext(), sym.MINUS, getLineNumber()); }
  "|"          { return new Token(yytext(), sym.BAR, getLineNumber()); }
  "assert"          { return new Token(yytext(), sym.ASSERT, getLineNumber()); }
  "!"          { return new Token(yytext(), sym.NOT, getLineNumber()); }
  "<"          { return new Token(yytext(), sym.LT, getLineNumber()); }
  "choose"          { return new Token(yytext(), sym.CHOOSE, getLineNumber()); }
  "in"          { return new Token(yytext(), sym.IN, getLineNumber()); }
  "("          { return new Token(yytext(), sym.LP, getLineNumber()); }
  ","          { return new Token(yytext(), sym.COMMA, getLineNumber()); }
  "lock"          { return new Token(yytext(), sym.LOCK, getLineNumber()); }
  ")"          { return new Token(yytext(), sym.RP, getLineNumber()); }
  "+"          { return new Token(yytext(), sym.PLUS, getLineNumber()); }
  "="          { return new Token(yytext(), sym.ASSIGN, getLineNumber()); }
  "if"          { return new Token(yytext(), sym.IF, getLineNumber()); }
  "."          { return new Token(yytext(), sym.DOT, getLineNumber()); }
  "}"          { return new Token(yytext(), sym.RCBR, getLineNumber()); }
  "&&"          { return new Token(yytext(), sym.LAND, getLineNumber()); }
  "return"          { return new Token(yytext(), sym.RETURN, getLineNumber()); }
  "new"          { return new Token(yytext(), sym.NEW, getLineNumber()); }
  "+="          { return new Token(yytext(), sym.ASSIGN_PLUS, getLineNumber()); }
  "||"          { return new Token(yytext(), sym.LOR, getLineNumber()); }
  "!="          { return new Token(yytext(), sym.NEQ, getLineNumber()); }
  "-="          { return new Token(yytext(), sym.ASSIGN_MINUS, getLineNumber()); }
  "=="          { return new Token(yytext(), sym.EQ, getLineNumber()); }
  ">="          { return new Token(yytext(), sym.GTE, getLineNumber()); }
  "*"          { return new Token(yytext(), sym.TIMES, getLineNumber()); }
  ":"          { return new Token(yytext(), sym.COLON, getLineNumber()); }
  "else"          { return new Token(yytext(), sym.ELSE, getLineNumber()); }
  "@"          { return new Token(yytext(), sym.AT, getLineNumber()); }
  ">"          { return new Token(yytext(), sym.GT, getLineNumber()); }
  "set"          { return new Token(yytext(), sym.SET, getLineNumber()); }
  
  {ILLEGALINTEGER}   { throw new LexicalError("Illegal integer with leadeing zeros <"+ yytext()+">"); }
  {INTEGER}   { return new Token(yytext(), sym.INT, getLineNumber(),Integer.parseInt(yytext())); }
  
  /* comments */
  {Comment}       { /* ignore */ }
  {WhiteSpace}                   { /* ignore */ }
  
  /* identifiers */ 
  {IDENTIFIER}    { return new Token(yytext(), sym.ID, getLineNumber(),yytext()); }
    
  
}
<STRINGSTATE> {
	\"                       { yybegin(YYINITIAL); return new Token(yytext(), sym.QUOTE, getLineNumber() ,string.toString()); }
	[^\n\r\"\\]+             { string.append( yytext() ); }
	/* escape sequences */
	\\t							{ string.append( '\t' ); }
	\\n							{ string.append( '\n' ); }
	\\r							{ string.append( '\r' ); }
	\\\"						{ string.append( '\"' ); }
	\\\\						{ string.append( '\\' ); }
	
	\\.								{ throw new LexicalError("Illegal escaping "+yytext()+""); }
	{LineTerminator}				{ throw new LexicalError("Unclosed string in line"); }
	<STRINGSTATE><<EOF>>			{ throw new LexicalError("Unclosed string in file"); }
}